#ifndef GX_META_PARSER_AUX_H
#define GX_META_PARSER_AUX_H

#include "Grammar.h"

namespace GxMetaParser
{


	template <typename T>
	T & GetClientObject(const RefPtr<ClientSymbolObject> & ptr)
	{
		return ((ClientSymbolObjectWrapper<T>*)(ptr.operator->()))->Value;
	}

	template <typename T>
	void SetClientObject(RefPtr<ClientSymbolObject> & obj, T value)
	{
		ClientSymbolObjectWrapper<T> * val = new ClientSymbolObjectWrapper<T>();
		val->Value = value;
		obj = val;
	}

	template <typename T>
	Array<T> & GetList(RefPtr<ClientSymbolObject> & obj)
	{
		return *(RefPtr<ClientSymbolObjectWrapper<RefPtr<Array<T>>>>(obj)->Value);
	}

	template <typename T>
	void __stdcall _ReductEmptyList(ReductionEventArgs & e)
	{
		SetClientObject(e.ReturnObject, RefPtr<Array<T>>(new Array<T>));
	}

	void __stdcall _ReductEmptyStringList(ReductionEventArgs & e);

	template<typename T, int objID>
	void __stdcall _ReductSingleList(ReductionEventArgs & e)
	{
		RefPtr<Array<T>> val = new Array<T>();
		val->Add(GetClientObject<T>(e.SymbolObjects[objID]->ClientObject));
		SetClientObject(e.ReturnObject, val);
	}

	template<int objID>
	void __stdcall _ReductSingleStringList(ReductionEventArgs & e)
	{
		RefPtr<Array<String>> val = new Array<String>();
		val->Add(e.SymbolObjects[objID]->TokenData.Str);
		SetClientObject(e.ReturnObject, val);
	}

	template<typename T, int listID, int objID>
	void __stdcall _ReductComposedList(ReductionEventArgs & e)
	{
		GetClientObject<RefPtr<Array<T>>>(e.SymbolObjects[listID]->ClientObject)->Add(GetClientObject<T>(e.SymbolObjects[objID]->ClientObject));
		e.ReturnObject = e.SymbolObjects[listID]->ClientObject;
	}
	template<int listID, int objID>
	void __stdcall _ReductComposedStringList(ReductionEventArgs & e)
	{
		GetClientObject<RefPtr<Array<String>>>(e.SymbolObjects[listID]->ClientObject)->Add(e.SymbolObjects[objID]->TokenData.Str);
		e.ReturnObject = e.SymbolObjects[listID]->ClientObject;
	}

	template<int objID>
	void __stdcall _CopyObject(ReductionEventArgs & e)
	{
		if (e.SymbolObjects.Count() > objID)
			e.ReturnObject = e.SymbolObjects[objID]->ClientObject;
	}

	template <int objID>
	ReductionEventHandler CopyObject()
	{
		ReductionEventHandler e;
		e.Bind(_CopyObject<objID>);
		return e;
	}

	template <typename T>
	ReductionEventHandler EmptyListReduction()
	{
		ReductionEventHandler e;
		e.Bind(_ReductEmptyList<T>);
		return e;
	}

	ReductionEventHandler EmptyStringListReduction();

	template <typename T, int objID>
	ReductionEventHandler SingleListReduction()
	{
		ReductionEventHandler e;
		e.Bind(_ReductSingleList<T, objID>);
		return e;
	}

	template <int objID>
	ReductionEventHandler SingleStringListReduction()
	{
		ReductionEventHandler e;
		e.Bind(_ReductSingleStringList<objID>);
		return e;
	}

	template <typename T, int listID, int objID>
	ReductionEventHandler ComposedListReduction()
	{
		ReductionEventHandler e;
		e.Bind(_ReductComposedList<T, listID, objID>);
		return e;
	}

	template <int listID, int objID>
	ReductionEventHandler ComposedStringListReduction()
	{
		ReductionEventHandler e;
		e.Bind(_ReductComposedStringList<listID, objID>);
		return e;
	}

	template <typename T>
	Array<T> & GetList(const RefPtr<ClientSymbolObject> & obj)
	{
		return GetClientObject<Array<T>>(obj);
	}

	template <typename T>
	void CopyList(const RefPtr<ClientSymbolObject> & obj, Array<T> & l)
	{
		l.Add(GetList(obj));
	}
}

#endif